﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "../GPSCNAVRAWMESSAGE.h"
#include "LogHeaderDecoder.h"

#include <algorithm>
#include <charconv>
#include <ranges>

namespace GnssLogs
{
namespace GPSCNAVRAWMESSAGEDecoder
{
using namespace tao::pegtl;
using Sync   = TAO_PEGTL_STRING("#GPSCNAVRAWMESSAGEA");
using Header = LogHeaderDecoder::SyncExpression<Sync>;
// clang-format off
struct SignalChannel : star<digit> {};
struct PRN : star<digit> {};
struct SignalType : star<alnum> {};
struct MessageID : star<digit> {};
struct RawData : rep<38*2, alnum> {};
// clang-format on

using Expression = seq<Header, SignalChannel, Split, PRN, Split, SignalType, Split, MessageID, Split, RawData, one<'*'>, CRC32, Tail>;

template<typename T>
struct Action
{
};

template<>
struct Action<Header> : LogHeaderDecoder::LogHeaderHelperNoSetValue
{
};

template<>
struct Action<SignalChannel> : IntHelper<Action<SignalChannel>, uint32_t>
{
    static void setValue(GPSCNAVRAWMESSAGE::Data& data, uint32_t value) { data.signalChannel = value; }
};

template<>
struct Action<PRN> : IntHelper<Action<PRN>, uint32_t>
{
    static void setValue(GPSCNAVRAWMESSAGE::Data& data, uint32_t value) { data.prn = value; }
};

template<>
struct Action<SignalType> : EnumHelper<Action<SignalType>, GPSCNAVRAWMESSAGE::SignalType>
{
    static void setValue(GPSCNAVRAWMESSAGE::Data& data, GPSCNAVRAWMESSAGE::SignalType value) { data.signalType = value; }
};

template<>
struct Action<MessageID> : IntHelper<Action<MessageID>, uint32_t>
{
    static void setValue(GPSCNAVRAWMESSAGE::Data& data, uint32_t value) { data.messageID = value; }
};

template<>
struct Action<RawData>
{
    template<typename ParseInput>
    static bool apply(ParseInput& in, GPSCNAVRAWMESSAGE::Data& data)
    {
        std::string str(in.begin(), in.size());
        auto view = str | std::views::chunk(2) |
                    std::views::transform([](const auto& view)
                                          { return static_cast<uint8_t>(std::stoul(std::string(view.begin(), view.end()), nullptr, 16)); });
        std::ranges::copy(view, data.data.begin());
        return true;
    }
};

template<>
struct Action<CRC32> : CRC32Helper<Action<CRC32>>
{
    static void setValue(GPSCNAVRAWMESSAGE::Data& data, uint32_t value) { data.crc32 = value; }
};
} // namespace GPSCNAVRAWMESSAGEDecoder
} // namespace GnssLogs